// project created on 11/23/2009 at 10:00 PM
// Compile:     c++ main.cpp -o FinalDB
// Run:         ./FinalDB

#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <iomanip>			// setprecision(2)
#include <time.h>			// clock()
#include <stdlib.h> 		// atoi, atof
using namespace std;

struct Result {
    int totalcostcount;
    double totalcostsum;
};

class Parts {
public:
    map< string, vector<double> > records;

    void load(ifstream &file) {
        string key, aux1, aux2;
        double totalcost;
        while (!getline(file, aux1, '|').eof()) { // partkey
            getline(file, aux2,'|'); 			// suppkey
            key = aux1 + "-" + aux2;		// key contatenation
            getline(file, aux1, '|');
            getline(file, aux2, '|');
            totalcost = atoi(aux1.c_str()) * atof(aux2.c_str());
            getline(file, aux1);					// read until newline
            records[key].push_back(totalcost);
        }
    }
};

class LineItems {
public:
    map< int, vector<double> > mapRecords;

    void load(ifstream &file, map< string, vector<double> > mapParts) {
        string key, aux1, aux2;
        int orderkey;
        while (!getline(file, aux1, '|').eof()) {
            orderkey = atoi(aux1.c_str());
            getline(file, aux1,'|'); 		// partkey
            getline(file, aux2,'|'); 		// suppkey
            key = aux1 + "-" + aux2;
            getline(file, aux1); 			// fix this, I need to move to newline
            vector<double> v = mapParts[key];
            for (int i=0; i<v.size();i++)
                mapRecords[orderkey].push_back(v[i]);
        }
    }
};

class Orders {
public:
    void loadAndGetResult(
        ifstream &file,
        map< int, vector<double> >& mapRecords,
        map<string,Result>& results) {
        int orderkey;
        string date, aux;
        Result r;
        while (!getline(file, aux, '|').eof()) {
            orderkey = atoi(aux.c_str());
            getline(file, aux,'|'); 	// custkey
            getline(file, aux,'|'); 	// orderstatus
            getline(file, aux,'|'); 	//	totalprice
            getline(file, date,'|');
            getline(file, aux); 		// fix this, I need to move to newline
            r = results[date];
            if (results.find(date) == results.end()) {
                r.totalcostcount = 0;
                r.totalcostsum = 0;
            }
            vector<double> v = mapRecords[orderkey];
            for (int j = 0; j < v.size(); ++j) {
                r.totalcostcount ++;
                r.totalcostsum += v[j];
            }
            results[date] = r;
        }
    }
};

int main (int argc, char *argv[])
{
    if(argc!=2) {
		cout << "Please type the parameter" << endl;
		exit(0);
	}
	double param = atof(argv[1]);

    // sum amount records with some key
    clock_t start, finish;
    start = clock();
    ifstream file1("partsupp.tbl") ;
    ifstream file2("lineitem.tbl") ;
    ifstream file3("orders.tbl") ;
    if (!file1 || !file2 || !file3)
        cout << "Could not open some file" << endl ;

    cout <<"Reading partsup.tbl..."<<endl;
    Parts parts;
    parts.load(file1);

    cout <<"Reading lineitem.tbl..."<<endl;
    LineItems items;
    items.load(file2, parts.records);

    cout <<"Reading orders.tbl..."<<endl;
    Orders orders;
    map<string,Result> results;
    orders.loadAndGetResult(file3, items.mapRecords, results);

    file1.close();
    file2.close();
    file3.close();

    //cout <<"Total records: "<< results.size() <<endl;

	double avg = 0.0;
	int lines = 0;
	// cout titles
    for (map<string,Result>::iterator i = results.begin(); i != results.end(); i++)
    {
	    avg = i->second.totalcostsum / double(i->second.totalcostcount);
	    if(avg < param)
	    {
        	cout << i->first << ": "
        	<< setw(14) << setiosflags(ios::fixed) /*<< setprecision(4)*/
        	<<  avg << endl;
        	lines++;
	    }
    }
    cout << "Total lines: " << lines << endl;

    finish = clock();
    cout << "Time: "<< (double(finish - start)/CLOCKS_PER_SEC) << endl;

    cout << "Ok"<< endl;
    //getchar();
    return 0;
}
